package com.cxria.springboottest.exception;

import com.cxria.springboottest.dto.Status;
import com.cxria.springboottest.enums.StatusCodeEnum;
import com.cxria.springboottest.enums.StatusMsgEnum;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.persistence.RollbackException;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;

@ControllerAdvice
public class DefaultExceptionHandler {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private ObjectMapper objectMapper;

	@ExceptionHandler(value = [Exception.class])
	@ResponseBody
	public Status exception(Exception ex) throws JsonProcessingException {
		Status status = null;
		String message;
		if(ex instanceof ConstraintViolationException){
			message = StatusMsgEnum.DATA_VIOLATION_ERROR + " : " + ex.getMessage();
			status = new Status(Status.ERROR, StatusCodeEnum.DATA_VIOLATION_ERROR, message);
		} else if(ex instanceof TransactionSystemException){
			Throwable ts = ex.getCause();
			if(ts instanceof RollbackException){
				Throwable re = ts.getCause();
				if(re instanceof ConstraintViolationException){
					message = StatusMsgEnum.DATA_VIOLATION_ERROR + " : " +re.getMessage();
					status = new Status(Status.ERROR, StatusCodeEnum.DATA_VIOLATION_ERROR, message);
				}
			} else {
				status = new Status(Status.ERROR, StatusCodeEnum.DATA_SAVE_ERROR, StatusMsgEnum.DATA_SAVE_ERROR);
			}
		} else {
			message = ex.getMessage();
			String msg = ex.getClass().getName() + " : " + message;
			try {
				status = objectMapper.readValue(message, Status.class);
				logger.error(objectMapper.writeValueAsString(status));
			} catch (Exception e) {
				status = new Status(Status.ERROR, StatusCodeEnum.UNKNOWN_ERROR, msg);
				logger.error(objectMapper.writeValueAsString(status));
			}
		}
		return status;
	}

}
